﻿using MDReader.Helper;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Collections;
using System.Reflection;

namespace MDReader.Services
{
    public interface ISettingService
    {
        void Register(ServiceProvider ServiceProvider);
        List<ISetting> ToList();
        void Set(string Name, string Value);
        string Get(string Name, string defaultValue = "");
        T? Get<T>(string Name);
        string Save();
    }
    public class SettingService : ISettingService
    {
        public SettingService(ILog log, IConfigurationService configurationService)
        {
            logger = log;
            config = configurationService;
        }

        private ILog logger;
        private readonly IConfigurationService config;
        List<ISetting> settings = new List<ISetting>();

        public void Register(ServiceProvider ServiceProvider)
        {
            var settingTypes = Assembly.GetExecutingAssembly()
                .GetTypes()
                .Where(t => typeof(ISetting).IsAssignableFrom(t) && t.IsClass && !t.IsAbstract);
            foreach (var settingType in settingTypes)
            {
                try
                {
                    var settingInstance = (ISetting)ServiceProvider.GetRequiredKeyedService(settingType, null);
                    {
                        settings.Add(settingInstance);
                    }
                }
                catch (Exception ex)
                {
                    logger.WriteExceptionToEventLog(ex);
                }
            }
        }
        public List<ISetting> ToList()
        {
            return settings;
        }

        public void Set(string Name, string Value)
        {
            config.SetSetting(Name, Value);
        }
        public string Get(string Name, string defaultValue = "")
        {
            return config.GetSetting(Name, defaultValue);
        }
        public T? Get<T>(string Name)
        {
            try
            {
                return settings.Where(s => s.SettingName == Name).First().Get<T>();
            }
            catch
            {
                return default;
            }
        }
        public string Save()
        {
            string ErrorMsg = "";
            foreach (var setting in settings)
            {
                ErrorMsg = setting.ConfirmEditor();
                if (!string.IsNullOrEmpty(ErrorMsg))
                    return ErrorMsg;
            }
            try
            {
                config.Save();
            }
            catch (Exception ex)
            { ErrorMsg = ex.Message; }
            return ErrorMsg;
        }
    }

    public interface ISetting
    {
        public string SettingName { get; }
        public string DefaultValue { get; }
        public ISettingTypes SettingType { get; }
        public string Value { get; set; }
        public T Get<T>();
        public string GetEditorValue();
        public Panel CreateEditorPanel();
        public string ConfirmEditor();

        public DataList? DataList { get; set; }
    }

    public enum ISettingTypes
    {
        Text,
        Combo,
        Check,
    }

    public abstract class SettingTemplate : ISetting
    {
        public SettingTemplate(ILog log, IConfigurationService configurationService)
        {
            logger = log;
            config = configurationService;
        }

        private ILog logger;
        private readonly IConfigurationService config;
        public virtual string SettingName => "";
        public virtual string DefaultValue => "";
        public virtual ISettingTypes SettingType { get; } = ISettingTypes.Text;
        public virtual string Value
        {
            get
            {
                try
                {
                    return config.GetSetting(SettingName, DefaultValue);
                }
                catch (Exception ex)
                { logger.WriteExceptionToEventLog(ex); }
                return DefaultValue;
            }
            set
            {
                try
                {
                    config.SetSetting(SettingName, value);
                }
                catch (Exception ex)
                { logger.WriteExceptionToEventLog(ex); }
            }
        }
        public virtual T? Get<T>()
        {
            if (typeof(T) == typeof(int))
            {
                int r = 0;
                try { int.TryParse(DefaultValue, out r); } catch { }
                try { int.TryParse(Value, out r); } catch { }
                return (T?)(object)r; // 显式转换
            }
            else if (typeof(T) == typeof(long))
            {
                long r = 0;
                try { long.TryParse(DefaultValue, out r); } catch { }
                try { long.TryParse(Value, out r); } catch { }
                return (T?)(object)r; // 显式转换
            }
            else if (typeof(T) == typeof(float))
            {
                float r = 0;
                try { float.TryParse(DefaultValue, out r); } catch { }
                try { float.TryParse(Value, out r); } catch { }
                return (T?)(object)r; // 显式转换
            }
            else if (typeof(T) == typeof(double))
            {
                double r = 0;
                try { double.TryParse(DefaultValue, out r); } catch { }
                try { double.TryParse(Value, out r); } catch { }
                return (T?)(object)r; // 显式转换
            }
            else if (typeof(T) == typeof(decimal))
            {
                decimal r = 0;
                try { decimal.TryParse(DefaultValue, out r); } catch { }
                try { decimal.TryParse(Value, out r); } catch { }
                return (T?)(object)r; // 显式转换
            }
            else if (typeof(T) == typeof(bool))
            {
                bool r = false;
                try { bool.TryParse(DefaultValue, out r); } catch { }
                try { bool.TryParse(Value, out r); } catch { }
                return (T?)(object)r; // 显式转换
            }
            else if (typeof(T) == typeof(string))
            {
                string r = Value;
                if (string.IsNullOrEmpty(r))
                    r = DefaultValue;
                return (T?)(object)r; // 显式转换
            }
            else if (typeof(T) == typeof(DateTime))
            {
                DateTime r = new DateTime();
                try { DateTime.TryParse(DefaultValue, out r); } catch { }
                try { DateTime.TryParse(Value, out r); } catch { }
                return (T?)(object)r; // 显式转换
            }
            else
            {
                try
                {
                    T? r = Newtonsoft.Json.JsonConvert.DeserializeObject<T>(DefaultValue);
                    return r;
                }
                catch
                {
                    return default;
                }
            }

        }
        private object? Editor { get; set; }
        public virtual DataList? DataList { get; set; }
        public virtual string GetEditorValue()
        {
            string value = "";
            switch (SettingType)
            {
                case ISettingTypes.Text:
                    if (Editor != null)
                    {
                        value = ((TextBox)Editor).Text;
                    }
                    break;
                case ISettingTypes.Combo:
                    if (Editor != null)
                    {
                        value = ((ComboBox)Editor).SelectedValue?.ToString() ?? "";
                    }
                    break;
                case ISettingTypes.Check:
                    if (Editor != null)
                    {
                        value = ((CheckBox)Editor).Checked.ToString();
                    }
                    break;
            }
            return value;
        }
        public virtual Panel CreateEditorPanel()
        {
            Panel p = new Panel() { Size = new Size(220, 35), Padding = new Padding(5) };
            switch (SettingType)
            {
                case ISettingTypes.Text:
                    {
                        Label l = new Label() { Text = SettingName, Dock = DockStyle.Left, Width = 55 };
                        TextBox t = new TextBox() { Dock = DockStyle.Fill, Text = Value };
                        p.Controls.Add(l);
                        p.Controls.Add(t);
                        Editor = t;
                    }
                    break;
                case ISettingTypes.Combo:
                    {
                        Label l = new Label() { Text = SettingName, Dock = DockStyle.Left, Width = 55 };
                        ComboBox t = new ComboBox() { Dock = DockStyle.Fill, Text = Value };
                        if (DataList != null && !string.IsNullOrEmpty(DataList.ValueMember))
                        {
                            t.DataSource = DataList.GetData();
                            t.ValueMember = DataList.ValueMember;
                            if (!string.IsNullOrEmpty(DataList.DisplayMember))
                                t.DisplayMember = DataList.DisplayMember;
                            else
                                t.DisplayMember = DataList.ValueMember;
                        }
                        p.Controls.Add(l);
                        p.Controls.Add(t);
                        Editor = t;
                    }
                    break;
                case ISettingTypes.Check:
                    {
                        bool isChecked = false;
                        try { bool.TryParse(DefaultValue, out isChecked); } catch { }
                        try { bool.TryParse(Value, out isChecked); } catch { }
                        CheckBox t = new CheckBox() { Dock = DockStyle.Fill, Text = SettingName, Checked = isChecked };
                        p.Controls.Add(t);
                        Editor = t;
                    }
                    break;
            }
            return p;
        }
        public virtual string ConfirmEditor()
        {
            try
            {
                string value = GetEditorValue();
                if (string.IsNullOrEmpty(value))
                    value = DefaultValue;
                Value = value;
                return string.Empty;
            }
            catch (Exception ex)
            { return ex.Message; }
        }


    }

    public class DataList
    {
        public virtual string DisplayMember { get; set; } = "";
        public virtual string ValueMember { get; set; } = "";

        public virtual DataView GetData()
        {
            return new DataView();
        }
    }
}
